package genetica.mutacion;

import java.util.Random;

import genetica.cromosomas.Cromosoma;
import genetica.cromosomas.GenesConAfinidad;
import genetica.cromosomas.genes.Gen;

public class MutacionAGenProximo extends AlgoritmoMutacion {
	private double probCercano;
	private int rango;

	public MutacionAGenProximo(double pMutacion, Integer rango,
			double probCercano) {
		super(pMutacion);
		this.setRango(rango);
		this.setProbCercano(probCercano);
	}

	@Override
	public void mutacion(Cromosoma original) {
		Random r = new Random();
		Class[] interfaces = original.getClass().getInterfaces();
		boolean finded = false;
		for (int i = 0; i < interfaces.length && !finded; i++) {
			Class interface_ = interfaces[i];
//			System.out.println(interface_.toString());
			if (interface_.equals(GenesConAfinidad.class)) {
				finded = true;
			}
		}
		if (!finded)
			throw new Error(
					"La clase no implementa la interfaz GenesComparables necesaria para esta mutacion");
		GenesConAfinidad cromosoma = (GenesConAfinidad) original;
		for (int i = 0; i < original.getGenes().size(); i++) {
			if (rango >= (original.getGenes().size() - 1))
				throw new Error("El número de genes no puede ser mayor que los genes del cromosoma");
			if (r.nextDouble() < pMutacion) {
				int pos = r.nextInt(rango);
				if (r.nextDouble() > probCercano) {
//					System.out.println("Mutado-A");
					pos = (original.getGenes().size() - pos)-2;
				}else {
//					System.out.println("Mutado-B");

				}
				int posicionRotada;
				Gen genMovido = null;
				if (i == (original.getGenes().size() - 1)){
					posicionRotada = 0;
				}
				else{
					posicionRotada = i + 1;
				}
				Gen genMutado = null;
				try {
					genMutado = cromosoma.genesProximos(i)[pos];
					
				} catch (Exception e) {
					// TODO: handle exception
				}
				genMovido = genMutado;

				boolean rotando = true;
				// genMutado constante el que pongo hay que ver si es el siguiente
				// siguiente pos valdrá la posicion donde tengo que guardar
				// genMovido el que hay que poner en la siguiente posicion
				int ciclos = 0;
				while (rotando) {
					ciclos++;
//					if (ciclos > 27)
//						System.out.println();
//					int siguientePos;
					Gen temp = original.getGenes().get(posicionRotada);
					try {
						if (temp.equals(genMutado)) {
							original.getGenes().set(posicionRotada, genMovido);
							rotando = false;
						} else {
							original.getGenes().set(posicionRotada, genMovido);
							genMovido = temp;
							if (posicionRotada == (original.getGenes().size() - 1)) {
								posicionRotada  = 0;
							} else {
								posicionRotada++;//  = posicionRotada + 1;
							}
						}
					} catch (Exception e) {
						// TODO: handle exception
					}

				}
			}
		}
	}

	public void setProbCercano(double probCercano) {
		this.probCercano = probCercano;
	}

	public double getProbCercano() {
		return probCercano;
	}

	public void setRango(int rango) {
		this.rango = rango;
	}

	public int getRango() {
		return rango;
	}
	
	public String toString(){
		return "Mutacion al gen más afin";  
	}

}
